//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2005-2007
//
// Object properties dialog - 'Route' page.
//

# include "StdAfx.h"
# include "Resource.h"
# include "RgnProperties.h"
# include "PropertyPages.h"
# include "Map.h"
# include "Rename.h"
# include "SetComment.h"
# include "ShowRgnOnMap.h"
# include "AltProfile.h"
# include "PrintUnits.h"
# include "Distance.h"
# include "Course.h"
# include "ListView.h"
# include "Static.h"
# include "Button.h"
# include "fast_floor.h"
# include "Settings.h"
# include "Globals.h"

enum {
	lvNumber      = 0,
	lvName        = 1,
	lvDistance    = 2,
	lvLegLength   = 3,
	lvCourse      = 4,
	lvPosition    = 5,
	lvAltitude    = 6,

	lvMax
};

void CRoutePage::_FillPoints () {
	ListView_DeleteAllItems (m_hList);

	bool bAltitudeDefined = false;

	if (m_rgn.elements.empty ())
		return;
	const points_t & points = m_rgn.elements [0].points;
	const size_t cPoints = points.size ();
	const routepoint_info_t * const pExtraPoints = m_rgn.pExtra ? m_rgn.pExtra->wtr.route ()->points.begin () : NULL;
	const size_t cExtraPoints = m_rgn.pExtra ? m_rgn.pExtra->wtr.route ()->points.size () : 0;

	double dDistance = 0;

	size_t cItem = 0;
	for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
		const point_t & point = points [cPoint];

		InsertItem (m_hList, cItem, cPoint, "%d", cPoint + 1);

		// Name.
		if (cPoint < cExtraPoints && pExtraPoints) {
			const rgn_t * const pWpt = pExtraPoints [cPoint].pWaypoint;
			if (pWpt)
				SetSubItemText (m_hList, cItem, lvName, "%s", pWpt->strLabel.c_str ());
		}

		if (cPoint + 1 < cPoints) {
			const point_t & point1 = points [cPoint + 1];

			// Distance.
			char strDistance [32];
			char strDistanceUnits [16];
			PrintDistance (strDistance, strDistanceUnits, dDistance);
			SetSubItemText (m_hList, cItem, lvDistance, "%s %s", strDistance, strDistanceUnits);

			const double dLeg = Distance (point, point1);
			dDistance += dLeg;

			// Leg length.
			PrintDistance (strDistance, strDistanceUnits, dLeg);
			SetSubItemText (m_hList, cItem, lvLegLength, "%s %s", strDistance, strDistanceUnits);

			// Course.
			if (dLeg != 0) {
				const double dCourse = Course (point, point1);
				char strCourse [32];
				PrintAzimuth (strCourse, dCourse);
				SetSubItemText (m_hList, cItem, lvCourse, "%s", strCourse);
			}
		} else {
			// Distance.
			char strDistance [32];
			char strDistanceUnits [16];
			PrintDistance (strDistance, strDistanceUnits, dDistance);
			SetSubItemText (m_hList, cItem, lvDistance, "%s %s", strDistance, strDistanceUnits);
		}

		// Position.
		char strPosition [64];
		PrintPosition (strPosition, point);
		SetSubItemText (m_hList, cItem, lvPosition, "%s", strPosition);

		// Altitude.
		if (cPoint < cExtraPoints && pExtraPoints) {
			const rgn_t * const pWpt = pExtraPoints [cPoint].pWaypoint;
			const waypoint_info_t * const pWptExtra = pWpt ? pWpt->pExtra->wtr.wpt () : NULL;
			if (pWptExtra && (pWptExtra->wFlags & waypoint_info_t::defAltitude) != 0) {
				char strAltitude [32];
				char strAltitudeUnit [16];
				PrintElevation (strAltitude, strAltitudeUnit, pWptExtra->fAltitude, unMeters, false);

				SetSubItemText (m_hList, cItem, lvAltitude, "%s %s", strAltitude, strAltitudeUnit);
				bAltitudeDefined = true;
			}
		}

		++ cItem;
	}

	if (! bAltitudeDefined)
		ListView_DeleteColumn (m_hList, lvAltitude);

	// Set the best width.
	AutoSizeColumns (m_hList);
}

bool CRoutePage::OnInit (HWND _hwndFocus) {
	// Label.
	SetDlgItemText (IDC_LABEL,   m_rgn.strLabel.c_str ());

	// Description.
	SetDlgItemText (IDC_COMMENT, m_rgn.strComment.c_str ());

	route_info_t * const pRtExtra = m_rgn.pExtra ? m_rgn.pExtra->wtr.route () : NULL;

	// Time.
	if (pRtExtra && (pRtExtra->wFlags & route_info_t::defTime) != 0) {
		// Get time zone bias + daylight saving time bias.
		TIME_ZONE_INFORMATION tzi;
		if (::GetTimeZoneInformation (& tzi) == TIME_ZONE_ID_DAYLIGHT)
			tzi.Bias += tzi.DaylightBias;

		SYSTEMTIME st;
		::VariantTimeToSystemTime (pRtExtra->dtTime - float (tzi.Bias)/(24*60), & st);

		char strDate [32];
		if (! ::GetDateFormat (LOCALE_USER_DEFAULT, DATE_LONGDATE, & st, NULL, strDate, sizeof (strDate)/sizeof (strDate [0])))
			strDate [0] = '\0';
		char strTime [32];
		if (! ::GetTimeFormat (LOCALE_USER_DEFAULT, 0, & st, NULL, strTime, sizeof (strTime)/sizeof (strTime [0])))
			strTime [0] = '\0';

		SetDlgItemTextF (IDC_TIME, "%s %s", strDate, strTime);
	}

	// Link.
	if (pRtExtra) {
		if (pRtExtra->strURL.empty ())
			EnableDlgItem (IDC_LINK_BROWSE, false);
		else
			SetDlgItemText (IDC_LINK, pRtExtra->strURL.c_str ());
	}
	SetButtonIcon (m_hWnd, IDC_LINK_BROWSE, IDI_BROWSE);

	// Points.
	m_hList = GetDlgItem (IDC_POINTS);
	ListView_SetExtendedListViewStyleEx (m_hList, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);

	AddColumn (m_hList, lvNumber,    "#",        true);
	AddColumn (m_hList, lvName,      "Waypoint");
	AddColumn (m_hList, lvDistance,  "Distance", true);
	AddColumn (m_hList, lvLegLength, "Leg",      true);
	AddColumn (m_hList, lvCourse,    "Course",   true);
	AddColumn (m_hList, lvPosition,  "Position");
	AddColumn (m_hList, lvAltitude,  "Altitude", true);
	AddColumn (m_hList, lvMax,       "");

	_FillPoints ();

	// Altitude profile.
	EnableDlgItem (IDC_ALT_PROFILE, IsAltitudeProfileDefined (m_rgn));

	return true;
}

void CRoutePage::OnCommand (WORD _wCmd, WORD _wNotifyCode, HWND _hwndCtl) {
	switch (_wCmd) {
		case IDC_LINK_BROWSE: {
			char strWebLink [256];
			GetDlgItemText (IDC_LINK, strWebLink, sizeof (strWebLink)/sizeof (strWebLink [0]));
			::ShellExecute (m_hWnd, NULL, strWebLink, NULL, NULL, SW_SHOWNORMAL);
			break;
		}

		case IDC_SHOW_ON_MAP:
			ShowRgnOnMap (m_rgn);
			break;

		case IDC_ALT_PROFILE:
			ShowAltitudeProfile (m_hWnd, m_rgn);
			break;

		case IDC_LABEL:
		case IDC_COMMENT:
		case IDC_LINK:
			if (_wNotifyCode == EN_UPDATE)
				PropSheetChanged ();
			break;
	}
}

bool CRoutePage::OnNotify (int _idCtrl, NMHDR * _pInfo) {
	switch (_pInfo->code) {
		case NM_RETURN:
		case NM_DBLCLK: {
			if (ListView_GetSelectedCount (m_hList) != 1)
				break;
			const size_t cSelItem = ListView_GetSelectionMark (m_hList);

			route_info_t * const pRteExtra = m_rgn.pExtra->wtr.route ();
			if (cSelItem >= pRteExtra->points.size ())
				break;
			routepoint_info_t & rpoint = pRteExtra->points [cSelItem];

			if (rpoint.pWaypoint)
				ShowRgnProperties (m_hWnd, * rpoint.pWaypoint);
			break;
		}
	}

	return CPage::OnNotify (_idCtrl, _pInfo);
}

void CRoutePage::OnApply (const PSHNOTIFY *) {
	// Label.
	const HWND hLabel = GetDlgItem (IDC_LABEL);
	const size_t cLabelLen = ::GetWindowTextLength (hLabel);
	char * const strLabel = reinterpret_cast<char *> (alloca (cLabelLen + 1));
	::GetWindowText (hLabel, strLabel, cLabelLen + 1);
	if (! (m_rgn.strLabel == strLabel))
		RenameObject (m_rgn, strLabel);

	// Comment.
	const HWND hComment = GetDlgItem (IDC_COMMENT);
	const size_t cCommentLen = ::GetWindowTextLength (hComment);
	char * const strComment = reinterpret_cast<char *> (alloca (cCommentLen + 1));
	::GetWindowText (hComment, strComment, cCommentLen + 1);
	if (! (m_rgn.strComment == strComment))
		SetComment (m_rgn, strComment);

	RefreshRequired ();
}
